﻿using HFUTCourseSimulation.Util;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;

/// <summary>
/// 用于保存到文件的课表数据。
/// 同时也是程序中作为转换核心的数据结构，各种课表数据之间的转换以该结构为核心。
/// </summary>
namespace HFUTCourseSimulation.Kernel.Data.Storage {

    /// <summary>
    /// 表示可以从旧版数据结构转换为最新版本的接口。
    /// </summary>
    public interface IFromLegacy {
        Semester ToLatest();
    }

    /// <summary>
    /// 学期数据
    /// </summary>
    public class Semester {
        public Semester() {
            StartDate = DateTime.Today;
            WeekCount = 20.ToString();
            IndexCount = 11.ToString();
            BreakfastAt = 0.ToString();
            LunchAt = 4.ToString();
            DinnerAt = 8.ToString();
            Courses = new List<Course>();
        }

        /// <summary>
        /// 学期开始日期（星期一）
        /// </summary>
        [JsonProperty("start_date", Required = Required.Always)]
        [JsonConverter(typeof(CustomDateTimeConverter))]
        public DateTime StartDate { get; set; }
        /// <summary>
        /// 教学周个数
        /// </summary>
        [JsonProperty("week_count", Required = Required.Always)]
        public string WeekCount { get; set; }
        /// <summary>
        /// 每天课程的节次数
        /// </summary>
        [JsonProperty("index_count", Required = Required.Always)]
        public string IndexCount { get; set; }
        /// <summary>
        /// 早餐插入在第几节次后
        /// </summary>
        [JsonProperty("breakfast_at", Required = Required.Always)]
        public string BreakfastAt { get; set; }
        /// <summary>
        /// 午餐插入在第几节次后
        /// </summary>
        [JsonProperty("lunch_at", Required = Required.Always)]
        public string LunchAt { get; set; }
        /// <summary>
        /// 晚餐插入在第几节次后
        /// </summary>
        [JsonProperty("dinner_at", Required = Required.Always)]
        public string DinnerAt { get; set; }
        /// <summary>
        /// 课程列表
        /// </summary>
        [JsonProperty("courses", Required = Required.Always)]
        public List<Course> Courses { get; set; }
    }

    public class Course {
        public Course() {
            Name = "";
            Description = "";
            Color = ColorTrans.ToStorageColorPair(Util.ColorPreset.MdColors.Indigo);
            Schedules = new List<Schedule>();
        }

        /// <summary>
        /// 课程的名称
        /// </summary>
        [JsonProperty("name", Required = Required.Always)]
        public string Name { get; set; }
        /// <summary>
        /// 课程的说明，例如教室位置，教师姓名等。
        /// </summary>
        [JsonProperty("description", Required = Required.Always)]
        public string Description { get; set; }
        /// <summary>
        /// 课程的颜色。
        /// </summary>
        [JsonProperty("color", Required = Required.Always)]
        public ColorPair Color { get; set; }
        /// <summary>
        /// 课程的所有安排
        /// </summary>
        [JsonProperty("schedules", Required = Required.Always)]
        public List<Schedule> Schedules { get; set; }
    }

    public class Schedule {
        public Schedule() {
            Week = "";
            Day = "";
            Index = "";
        }

        /// <summary>
        /// 安排在哪些周
        /// </summary>
        [JsonProperty("week", Required = Required.Always)]
        public string Week { get; set; }
        /// <summary>
        /// 安排在周的星期几
        /// </summary>
        [JsonProperty("day", Required = Required.Always)]
        public string Day { get; set; }
        /// <summary>
        /// 安排在这些日子的哪些节次
        /// </summary>
        [JsonProperty("index", Required = Required.Always)]
        public string Index { get; set; }
    }

    /// <summary>
    /// 课程颜色对，包含前景色和背景色
    /// </summary>
    public class ColorPair {
        public ColorPair() {
            Foreground = Colors.Black;
            Background = Colors.White;
        }

        /// <summary>
        /// 前景色（文本）
        /// </summary>
        [JsonProperty("foreground", Required = Required.Always)]
        [JsonConverter(typeof(CustomColorConverter))]
        public Color Foreground { get; set; }
        /// <summary>
        /// 背景色（背景）
        /// </summary>
        [JsonProperty("background", Required = Required.Always)]
        [JsonConverter(typeof(CustomColorConverter))]
        public Color Background { get; set; }
    }

    internal class CustomDateTimeConverter : JsonConverter<DateTime> {
        private static readonly string DatetimeFormat = "yyyy-MM-dd";

        public override DateTime ReadJson(JsonReader reader, Type objectType, DateTime existingValue, bool hasExistingValue, JsonSerializer serializer) {
            if (reader.TokenType == JsonToken.String) {
                var value = reader.Value as string;
                if (DateTime.TryParseExact(value, DatetimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime rv)) {
                    return rv;
                } else {
                    throw new JsonSerializationException($"given string can not be parsed as DateTime: {value}");
                }
            } else {
                throw new JsonSerializationException($"expect a string but got {reader.TokenType}");
            }
        }

        public override void WriteJson(JsonWriter writer, DateTime value, JsonSerializer serializer) {
            writer.WriteValue(value.ToString(DatetimeFormat, CultureInfo.InvariantCulture));
        }
    }

    internal class CustomColorConverter : JsonConverter<Color> {
        public override Color ReadJson(JsonReader reader, Type objectType, Color existingValue, bool hasExistingValue, JsonSerializer serializer) {
            if (reader.TokenType == JsonToken.Integer) {
                var argb = Convert.ToInt32(reader.Value);
                return ColorTrans.ToWpfColor(argb);
            } else {
                throw new JsonSerializationException($"expect a integer but got {reader.TokenType}");
            }
        }

        public override void WriteJson(JsonWriter writer, Color value, JsonSerializer serializer) {
            writer.WriteValue(ColorTrans.ToInt(value));
        }
    }

}
